مجموعه داده کیفیت شراب که توسط Cortez و همکارانش در سال ۲۰۰۹ گردآوری شده، شامل اطلاعات شرابهای قرمز و سفید منطقه Vinho Verde در شمال پرتغال است. این دیتاست در واقع تلاشی برای پل زدن میان دو دنیای متفاوت است: دنیای دقیق و قابل اندازهگیری شیمی، و دنیای ذهنی و حسی ارزیابی انسانی.
شرابها بر اساس ۱۱ ویژگی فیزیکوشیمیایی توصیف شدهاند که همگی به صورت کمی قابل سنجش هستند - از میزان اسیدهای مختلف گرفته تا چگالی و درصد الکل. اما خروجی مورد نظر، یعنی متغیر کیفیت (Quality)، حاصل قضاوت حسی سه کارشناس است که نمرهای بین ۰ تا ۱۰ به هر نمونه دادهاند.
البته نکته جالب این است که در عمل، هیچ شرابی نمره صفر یا ده نگرفته. تمام امتیازها در بازه ۳ تا ۸ قرار دارند که این موضوع خود بیانگر محدودیت طبیعی دادههاست. برای تسهیل تحلیل، معمولاً این امتیازها به دو دسته کیفیت بالا (HIGH) و کیفیت پایین (LOW) تقسیم میشوند تا مسئله از حالت رگرسیون به طبقهبندی دودویی تبدیل شود.
در جدول زیر، توضیح مختصری از هر یک از متغیرهای موجود در دیتاست آورده شده است:
| نام انگلیسی | ترجمه فارسی | توضیحات فنی |
|---|---|---|
| Fixed Acidity | اسیدیته ثابت | اسیدهای غیرفراری که در شراب به صورت طبیعی وجود دارند (مانند اسید تارتاریک) |
| Volatile Acidity | اسیدیته فرار | اسیدهایی که تبخیر میشوند؛ میزان بالا نشانه فساد احتمالی است |
| Citric Acid | اسید سیتریک | مسئول طراوت و تیزی طعم؛ در مقادیر کم به عنوان نگهدارنده عمل میکند |
| Residual Sugar | قند باقیمانده | قندی که پس از تخمیر در شراب باقی میماند |
| Chlorides | کلریدها | میزان نمک موجود در شراب |
| Free Sulfur Dioxide | دیاکسید گوگرد آزاد | فرم فعال SO₂ که از اکسیداسیون و رشد میکروبها جلوگیری میکند |
| Total Sulfur Dioxide | دیاکسید گوگرد کل | مجموع اشکال آزاد و متصل SO₂ |
| Density | چگالی | جرم حجمی مایع که به میزان الکل و قند بستگی دارد |
| pH | پیاچ | سطح اسیدی یا بازی بودن (مقیاس ۰ تا ۱۴) |
| Sulphates | سولفاتها | افزودنیهایی برای نگهداری و جلوگیری از اکسیداسیون |
| Alcohol | الکل | درصد الکل موجود در شراب |
| Quality | کیفیت | امتیاز حسی (متغیر هدف): HIGH یا LOW |
| Id | شناسه | شماره ردیف (بدون ارزش تحلیلی) |
اولین گام در هر پروژه تحلیل داده، بارگذاری کتابخانههای ضروری است. در این پژوهش از مجموعهای از ابزارهای قدرتمند R برای پیشپردازش، تحلیل اکتشافی و مدلسازی استفاده شده است.
library(caret)
library(class)
library(skimr)
library(corrplot)
library(DataExplorer)
library(SmartEDA)
library(summarytools)نقش ابزارهای منتخب:
هسته اصلی پردازش و مدلسازی در این پروژه بر عهده پکیج قدرتمند caret است که فرآیندهای آموزش و ارزیابی را یکپارچه میسازد. برای تحلیلهای آماری اولیه و درک سریع ساختار دادهها از skimr و DataExplorer بهره بردهایم. همچنین جهت بررسی همبستگی متغیرها که در حذف ویژگیهای زائد حیاتی است، از corrplot استفاده شده است.
دادههای خام بهصورت مستقیم از مخزن گیتهاب پروژه بارگذاری میشوند. این روش دسترسی، تکرارپذیری کد را برای سایر پژوهشگران تضمین میکند.
data <- read.csv("https://raw.githubusercontent.com/sainsdataid/dataset/main/wine-quality-binary.csv")بررسی اولیه ساختار داده:
پس از بارگذاری، ضروری است تا با استفاده از توابع skim و
str، نگاهی اجمالی به ابعاد، نوع متغیرها و سلامت کلی دادهها
داشته باشیم. این گام به ما کمک میکند تا استراتژی مناسبی برای پیشپردازش
اتخاذ کنیم.
| Name | data |
| Number of rows | 1143 |
| Number of columns | 13 |
| _______________________ | |
| Column type frequency: | |
| character | 1 |
| numeric | 12 |
| ________________________ | |
| Group variables | None |
Variable type: character
| skim_variable | n_missing | complete_rate | min | max | empty | n_unique | whitespace |
|---|---|---|---|---|---|---|---|
| quality | 0 | 1 | 3 | 4 | 0 | 2 | 0 |
Variable type: numeric
| skim_variable | n_missing | complete_rate | mean | sd | p0 | p25 | p50 | p75 | p100 | hist |
|---|---|---|---|---|---|---|---|---|---|---|
| id | 0 | 1 | 572.00 | 330.10 | 1.00 | 286.50 | 572.00 | 857.50 | 1143.00 | ▇▇▇▇▇ |
| fixed.acidity | 0 | 1 | 8.31 | 1.75 | 4.60 | 7.10 | 7.90 | 9.10 | 15.90 | ▂▇▂▁▁ |
| volatile.acidity | 0 | 1 | 0.53 | 0.18 | 0.12 | 0.39 | 0.52 | 0.64 | 1.58 | ▅▇▂▁▁ |
| citric.acid | 0 | 1 | 0.27 | 0.20 | 0.00 | 0.09 | 0.25 | 0.42 | 1.00 | ▇▆▅▁▁ |
| residual.sugar | 0 | 1 | 2.53 | 1.36 | 0.90 | 1.90 | 2.20 | 2.60 | 15.50 | ▇▁▁▁▁ |
| chlorides | 0 | 1 | 0.09 | 0.05 | 0.01 | 0.07 | 0.08 | 0.09 | 0.61 | ▇▁▁▁▁ |
| free.sulfur.dioxide | 0 | 1 | 15.62 | 10.25 | 1.00 | 7.00 | 13.00 | 21.00 | 68.00 | ▇▅▂▁▁ |
| total.sulfur.dioxide | 0 | 1 | 45.91 | 32.78 | 6.00 | 21.00 | 37.00 | 61.00 | 289.00 | ▇▂▁▁▁ |
| density | 0 | 1 | 1.00 | 0.00 | 0.99 | 1.00 | 1.00 | 1.00 | 1.00 | ▁▃▇▂▁ |
| pH | 0 | 1 | 3.31 | 0.16 | 2.74 | 3.20 | 3.31 | 3.40 | 4.01 | ▁▅▇▂▁ |
| sulphates | 0 | 1 | 0.66 | 0.17 | 0.33 | 0.55 | 0.62 | 0.73 | 2.00 | ▇▅▁▁▁ |
| alcohol | 0 | 1 | 10.44 | 1.08 | 8.40 | 9.50 | 10.20 | 11.10 | 14.90 | ▇▇▃▁▁ |
## 'data.frame': 1143 obs. of 13 variables:
## $ id : int 1 2 3 4 5 6 7 8 9 10 ...
## $ fixed.acidity : num 7.4 7.8 7.8 11.2 7.4 7.4 7.9 7.3 7.8 6.7 ...
## $ volatile.acidity : num 0.7 0.88 0.76 0.28 0.7 0.66 0.6 0.65 0.58 0.58 ...
## $ citric.acid : num 0 0 0.04 0.56 0 0 0.06 0 0.02 0.08 ...
## $ residual.sugar : num 1.9 2.6 2.3 1.9 1.9 1.8 1.6 1.2 2 1.8 ...
## $ chlorides : num 0.076 0.098 0.092 0.075 0.076 0.075 0.069 0.065 0.073 0.097 ...
## $ free.sulfur.dioxide : num 11 25 15 17 11 13 15 15 9 15 ...
## $ total.sulfur.dioxide: num 34 67 54 60 34 40 59 21 18 65 ...
## $ density : num 0.998 0.997 0.997 0.998 0.998 ...
## $ pH : num 3.51 3.2 3.26 3.16 3.51 3.51 3.3 3.39 3.36 3.28 ...
## $ sulphates : num 0.56 0.68 0.65 0.58 0.56 0.56 0.46 0.47 0.57 0.54 ...
## $ alcohol : num 9.4 9.8 9.8 9.8 9.4 9.4 9.4 10 9.5 9.2 ...
## $ quality : chr "LOW" "LOW" "LOW" "HIGH" ...
در این مرحله، ستون id که صرفاً شناسهای برای ردیفهاست و
فاقد ارزش اطلاعاتی برای مدلسازی است، حذف میگردد. همچنین، متغیر هدف
(quality) که ماهیت طبقهای دارد، به ساختار
Factor تبدیل میشود تا برای الگوریتمهای طبقهبندی قابل
فهم باشد.
یکی از چالشهای رایج در یادگیری ماشین، عدم توازن دادههاست. در اینجا توزیع فراوانی متغیر هدف را بررسی میکنیم تا مطمئن شویم مدل دچار اریبی به سمت کلاس غالب نخواهد شد.
quality <- data.frame(table(data$quality))
quality$Prop <- round(quality$Freq/sum(quality$Freq), 3)
print(quality)## Var1 Freq Prop
## 1 HIGH 621 0.543
## 2 LOW 522 0.457
تحلیل توزیع کلاسها:
بررسی جدول فوق نشان میدهد که دادهها از نظر توزیع کلاسها نسبتاً متعادل (Balanced) هستند (حدود ۵۴٪ در برابر ۴۶٪). این خبر خوبی است، زیرا نیاز به تکنیکهای پیچیده نمونهبرداری (مانند SMOTE) را مرتفع میسازد و میتوانیم با اطمینان بیشتری به سراغ مدلسازی برویم.
پیش از هرگونه مدلسازی، باید درک عمیقی از رفتار متغیرها داشته باشیم. نمودارها و آمارههای زیر به ما در شناسایی دادههای پرت و الگوی توزیع ویژگیها کمک میکنند.
st_options(plain.ascii = FALSE, style = "rmarkdown")
print(dfSummary(data, graph.magnif = 0.75), method = "pander")## ### Data Frame Summary
## #### data
## **Dimensions:** 1143 x 12
## **Duplicates:** 125
##
## -------------------------------------------------------------------------------------------------------------------------
## No Variable Stats / Values Freqs (% of Valid) Graph Valid Missing
## ---- ----------------------- -------------------------- --------------------- ---------------------- ---------- ---------
## 1 fixed.acidity\ Mean (sd) : 8.3 (1.7)\ 91 distinct values \ \ \ \ :\ 1143\ 0\
## [numeric] min < med < max:\ \ \ \ \ : .\ (100.0%) (0.0%)
## 4.6 < 7.9 < 15.9\ \ \ \ \ : :\
## IQR (CV) : 2 (0.2) \ \ : : : .\
## . : : : : : . .
##
## 2 volatile.acidity\ Mean (sd) : 0.5 (0.2)\ 135 distinct values \ \ \ \ . :\ 1143\ 0\
## [numeric] min < med < max:\ \ \ : : :\ (100.0%) (0.0%)
## 0.1 < 0.5 < 1.6\ \ \ : : :\
## IQR (CV) : 0.2 (0.3) \ \ : : : .\
## . : : : : .
##
## 3 citric.acid\ Mean (sd) : 0.3 (0.2)\ 77 distinct values :\ 1143\ 0\
## [numeric] min < med < max:\ : \ \ .\ (100.0%) (0.0%)
## 0 < 0.2 < 1\ : \ \ : . .\
## IQR (CV) : 0.3 (0.7) : : : : : .\
## : : : : : : .
##
## 4 residual.sugar\ Mean (sd) : 2.5 (1.4)\ 80 distinct values :\ 1143\ 0\
## [numeric] min < med < max:\ :\ (100.0%) (0.0%)
## 0.9 < 2.2 < 15.5\ : .\
## IQR (CV) : 0.7 (0.5) : :\
## : : . .
##
## 5 chlorides\ Mean (sd) : 0.1 (0)\ 131 distinct values \ \ :\ 1143\ 0\
## [numeric] min < med < max:\ \ \ :\ (100.0%) (0.0%)
## 0 < 0.1 < 0.6\ \ \ :\
## IQR (CV) : 0 (0.5) : :\
## : :
##
## 6 free.sulfur.dioxide\ Mean (sd) : 15.6 (10.3)\ 53 distinct values . :\ 1143\ 0\
## [numeric] min < med < max:\ : : :\ (100.0%) (0.0%)
## 1 < 13 < 68\ : : :\
## IQR (CV) : 14 (0.7) : : : : .\
## : : : : : .
##
## 7 total.sulfur.dioxide\ Mean (sd) : 45.9 (32.8)\ 138 distinct values :\ 1143\ 0\
## [numeric] min < med < max:\ :\ (100.0%) (0.0%)
## 6 < 37 < 289\ : :\
## IQR (CV) : 40 (0.7) : : .\
## : : : . .
##
## 8 density\ Mean (sd) : 1 (0)\ 388 distinct values \ \ \ \ \ \ \ \ : .\ 1143\ 0\
## [numeric] min < med < max:\ \ \ \ \ \ \ \ \ : :\ (100.0%) (0.0%)
## 1 < 1 < 1\ \ \ \ \ \ \ : : :\
## IQR (CV) : 0 (0) \ \ \ \ \ \ : : : :\
## \ \ . : : : : : .
##
## 9 pH\ Mean (sd) : 3.3 (0.2)\ 87 distinct values \ \ \ \ \ \ \ \ :\ 1143\ 0\
## [numeric] min < med < max:\ \ \ \ \ \ \ . :\ (100.0%) (0.0%)
## 2.7 < 3.3 < 4\ \ \ \ \ \ \ : : :\
## IQR (CV) : 0.2 (0) \ \ \ \ \ \ : : : .\
## \ \ . : : : : :
##
## 10 sulphates\ Mean (sd) : 0.7 (0.2)\ 89 distinct values \ \ :\ 1143\ 0\
## [numeric] min < med < max:\ \ \ :\ (100.0%) (0.0%)
## 0.3 < 0.6 < 2\ \ \ : .\
## IQR (CV) : 0.2 (0.3) \ \ : :\
## : : : .
##
## 11 alcohol\ Mean (sd) : 10.4 (1.1)\ 61 distinct values \ \ :\ 1143\ 0\
## [numeric] min < med < max:\ \ \ :\ (100.0%) (0.0%)
## 8.4 < 10.2 < 14.9\ \ \ : : :\
## IQR (CV) : 1.6 (0.1) \ \ : : : . .\
## . : : : : : :
##
## 12 quality\ 1\. HIGH\ 621 (54.3%)\ IIIIIIIIII \ 1143\ 0\
## [factor] 2\. LOW 522 (45.7%) IIIIIIIII (100.0%) (0.0%)
## -------------------------------------------------------------------------------------------------------------------------
نکات کلیدی حاصل از EDA:
plot_intro فقدان دادههای گمشده (Missing Values)
را تأیید میکند که فرآیند پاکسازی را تسهیل مینماید.ExpNumStat وجود دادههای پرت در برخی ویژگیهای
شیمیایی را نشان میدهد، اما با توجه به ماهیت دادههای آزمایشگاهی، این
مقادیر میتوانند واقعی باشند و نه خطا.برای سنجش واقعی عملکرد مدل، دادهها را با نسبت ۷۰ به ۳۰ افراز میکنیم. استفاده از روش نمونهگیری طبقهای (Stratified Sampling) تضمین میکند که نسبت کیفیت خوب به بد در هر دو بخش آموزش و آزمون یکسان باقی بماند.
set.seed(251222)
trainindex <- createDataPartition(data$quality, p = 0.7, list = FALSE, times = 1)
data.train <- data[trainindex, ]
data.test <- data[-trainindex, ]
cbind("train" = table(data.train$quality), "test" = table(data.test$quality))## train test
## HIGH 435 186
## LOW 366 156
پس از تقسیم دادهها، باید مطمئن شویم که روابط آماری میان متغیرها مخدوش نشده است. ماتریسهای همبستگی زیر این موضوع را بررسی میکنند.
par(mfrow=c(1, 3))
corrplot(cor(Filter(is.numeric, data)),
method = "color",
title = "Original Data",
mar=c(0,0,2,0))
corrplot(cor(Filter(is.numeric, data.train)),
method = "color",
title = "Train Data",
mar=c(0,0,2,0))
corrplot(cor(Filter(is.numeric, data.test)),
method = "color",
title = "Test Data",
mar=c(0,0,2,0))تفسیر همبستگیها:
شباهت بصری بسیار زیاد بین سه نمودار فوق، یک نشانه عالی است. این امر تأیید میکند که دادههای آموزشی ما نمایندهای صادق از کل جامعه آماری هستند و روابط بین متغیرها (مثلاً رابطه مثبت بین چگالی و اسیدیته ثابت) در فرآیند افراز داده حفظ شده است.
الگوریتم KNN بر پایه محاسبه فاصله (اقلیدسی) عمل میکند. متغیرهایی با مقادیر عددی بزرگ میتوانند بر متغیرهای کوچک سایه بیندازند. برای رفع این مشکل، تمام متغیرهای عددی را به بازه [0, 1] نرمالسازی میکنیم.
preproc.params <- preProcess(data.train[, -12], method = "range")
scaled.data.train <- predict(preproc.params, data.train[, -12])
scaled.data.test <- predict(preproc.params, data.test[, -12])
summary(scaled.data.train)## fixed.acidity volatile.acidity citric.acid residual.sugar
## Min. :0.0000 Min. :0.0000 Min. :0.0000 Min. :0.00000
## 1st Qu.:0.2273 1st Qu.:0.1918 1st Qu.:0.0900 1st Qu.:0.06897
## Median :0.3000 Median :0.2740 Median :0.2400 Median :0.08966
## Mean :0.3344 Mean :0.2819 Mean :0.2641 Mean :0.11321
## 3rd Qu.:0.4091 3rd Qu.:0.3562 3rd Qu.:0.4200 3rd Qu.:0.11724
## Max. :1.0000 Max. :1.0000 Max. :1.0000 Max. :1.00000
## chlorides free.sulfur.dioxide total.sulfur.dioxide density
## Min. :0.00000 Min. :0.00000 Min. :0.00000 Min. :0.0000
## 1st Qu.:0.09683 1st Qu.:0.08955 1st Qu.:0.05515 1st Qu.:0.4031
## Median :0.11185 Median :0.17910 Median :0.11029 Median :0.4824
## Mean :0.12606 Mean :0.21555 Mean :0.14243 Mean :0.4894
## 3rd Qu.:0.13189 3rd Qu.:0.29851 3rd Qu.:0.19853 3rd Qu.:0.5712
## Max. :1.00000 Max. :1.00000 Max. :1.00000 Max. :1.0000
## pH sulphates alcohol
## Min. :0.0000 Min. :0.0000 Min. :0.0000
## 1st Qu.:0.3622 1st Qu.:0.1317 1st Qu.:0.1964
## Median :0.4488 Median :0.1737 Median :0.3214
## Mean :0.4514 Mean :0.1943 Mean :0.3640
## 3rd Qu.:0.5276 3rd Qu.:0.2335 3rd Qu.:0.4821
## Max. :1.0000 Max. :1.0000 Max. :1.0000
برای یافتن بهترین تعداد همسایه (k)، از روش اعتبارسنجی متقابل ۱۰ لایه استفاده شده است. ما مقادیر مختلف k (از ۱ تا ۳۵) را آزمایش میکنیم.
ctrl <- trainControl(method = "cv",
number = 10,
classProbs = TRUE,
summaryFunction = twoClassSummary)
grid <- expand.grid(k = seq(1, 35, by = 1))
set.seed(123)
knn_fit <- train(quality ~ .,
data = data.train,
method = "knn",
trControl = ctrl,
tuneGrid = grid,
metric = "ROC")
print(knn_fit)## k-Nearest Neighbors
##
## 801 samples
## 11 predictor
## 2 classes: 'HIGH', 'LOW'
##
## No pre-processing
## Resampling: Cross-Validated (10 fold)
## Summary of sample sizes: 720, 721, 721, 722, 721, 721, ...
## Resampling results across tuning parameters:
##
## k ROC Sens Spec
## 1 0.6395686 0.6369450 0.6421922
## 2 0.6534987 0.6346723 0.5930180
## 3 0.6644854 0.6737844 0.5846096
## 4 0.6691036 0.6460359 0.6252252
## 5 0.6735242 0.6575581 0.6040541
## 6 0.6742145 0.6713531 0.5873123
## 7 0.6704632 0.6714588 0.5681682
## 8 0.6785554 0.6643235 0.5874625
## 9 0.6860569 0.6804440 0.6092342
## 10 0.6880843 0.7009514 0.6064565
## 11 0.6990067 0.6894292 0.6093093
## 12 0.7049096 0.6941332 0.6095345
## 13 0.7024106 0.7008985 0.6202703
## 14 0.7020320 0.7030127 0.6148649
## 15 0.7046046 0.6986258 0.6254505
## 16 0.7037783 0.6987315 0.6144895
## 17 0.7016306 0.6894292 0.6090841
## 18 0.7027243 0.6939218 0.6090841
## 19 0.6989746 0.6893763 0.5955706
## 20 0.7005414 0.7056025 0.6010511
## 21 0.6999189 0.7056025 0.5874625
## 22 0.6997701 0.7080867 0.5821321
## 23 0.7053252 0.7217230 0.5957207
## 24 0.7033227 0.7217230 0.6037538
## 25 0.7042287 0.7171776 0.5958709
## 26 0.7065551 0.7193446 0.5846847
## 27 0.7034810 0.7146406 0.5929429
## 28 0.7052123 0.7216702 0.5792042
## 29 0.7061664 0.7215645 0.5765015
## 30 0.7037258 0.7216702 0.5681682
## 31 0.7022616 0.7284884 0.5601351
## 32 0.7035852 0.7308140 0.5710961
## 33 0.7008683 0.7353594 0.5629129
## 34 0.7025120 0.7422833 0.5737988
## 35 0.7058676 0.7468816 0.5602102
##
## ROC was used to select the optimal model using the largest value.
## The final value used for the model was k = 26.
بهینهسازی پارامتر K:
نمودار فوق روند تغییرات عملکرد مدل را نشان میدهد. مشاهده میشود که با افزایش k، ابتدا دقت بهبود مییابد و سپس به ثبات میرسد. الگوریتم بر اساس معیار ROC، مقدار بهینه را پیشنهاد داده است. این انتخاب تعادل مناسبی بین واریانس و بایاس برقرار میکند.
اکنون مدل نهایی را با k بهینه روی دادههای آزمون اجرا میکنیم تا عملکرد واقعی آن مشخص شود.
pred.knn <- knn(train=scaled.data.train, test=scaled.data.test,
cl=data.train$quality, k=31)
print(pred.knn)## [1] LOW LOW LOW HIGH LOW LOW HIGH HIGH HIGH LOW LOW LOW LOW LOW HIGH
## [16] LOW LOW LOW LOW LOW HIGH LOW LOW LOW LOW LOW HIGH LOW HIGH LOW
## [31] LOW LOW LOW HIGH LOW LOW LOW LOW LOW LOW LOW LOW LOW HIGH LOW
## [46] LOW HIGH LOW LOW LOW LOW LOW HIGH LOW HIGH HIGH LOW HIGH HIGH LOW
## [61] HIGH HIGH HIGH HIGH HIGH HIGH LOW HIGH LOW LOW LOW HIGH LOW HIGH HIGH
## [76] HIGH LOW HIGH HIGH HIGH HIGH HIGH HIGH HIGH HIGH LOW HIGH HIGH HIGH HIGH
## [91] HIGH HIGH HIGH LOW LOW LOW HIGH LOW HIGH LOW LOW HIGH LOW HIGH HIGH
## [106] HIGH HIGH HIGH HIGH HIGH HIGH HIGH HIGH HIGH HIGH LOW HIGH HIGH HIGH HIGH
## [121] HIGH LOW HIGH HIGH HIGH HIGH HIGH HIGH HIGH LOW HIGH LOW HIGH LOW LOW
## [136] LOW LOW HIGH HIGH HIGH LOW LOW LOW HIGH LOW HIGH HIGH HIGH LOW HIGH
## [151] LOW LOW LOW LOW HIGH LOW LOW LOW HIGH HIGH LOW LOW LOW HIGH HIGH
## [166] LOW LOW LOW HIGH LOW HIGH HIGH HIGH LOW LOW LOW LOW LOW HIGH LOW
## [181] HIGH LOW LOW HIGH LOW LOW HIGH HIGH HIGH HIGH LOW HIGH HIGH HIGH HIGH
## [196] LOW LOW HIGH HIGH HIGH LOW LOW HIGH HIGH HIGH HIGH HIGH HIGH HIGH LOW
## [211] HIGH HIGH HIGH HIGH LOW HIGH HIGH LOW HIGH HIGH LOW HIGH HIGH HIGH HIGH
## [226] HIGH HIGH HIGH HIGH HIGH HIGH HIGH HIGH LOW HIGH HIGH HIGH HIGH HIGH HIGH
## [241] HIGH HIGH LOW HIGH HIGH HIGH HIGH HIGH LOW HIGH HIGH LOW LOW LOW LOW
## [256] HIGH HIGH HIGH LOW LOW HIGH LOW HIGH HIGH LOW LOW HIGH HIGH HIGH HIGH
## [271] LOW LOW LOW HIGH LOW HIGH HIGH HIGH HIGH LOW LOW LOW HIGH LOW LOW
## [286] LOW HIGH HIGH HIGH LOW HIGH LOW LOW HIGH LOW HIGH LOW LOW HIGH LOW
## [301] HIGH HIGH LOW HIGH LOW HIGH LOW HIGH HIGH HIGH HIGH HIGH HIGH HIGH LOW
## [316] HIGH LOW HIGH HIGH HIGH HIGH LOW HIGH LOW HIGH LOW HIGH HIGH HIGH LOW
## [331] LOW HIGH LOW LOW HIGH HIGH LOW HIGH HIGH HIGH HIGH HIGH
## Levels: HIGH LOW
## Confusion Matrix and Statistics
##
## Reference
## Prediction HIGH LOW
## HIGH 145 51
## LOW 41 105
##
## Accuracy : 0.731
## 95% CI : (0.6807, 0.7773)
## No Information Rate : 0.5439
## P-Value [Acc > NIR] : 8.407e-13
##
## Kappa : 0.455
##
## Mcnemar's Test P-Value : 0.3481
##
## Sensitivity : 0.7796
## Specificity : 0.6731
## Pos Pred Value : 0.7398
## Neg Pred Value : 0.7192
## Prevalence : 0.5439
## Detection Rate : 0.4240
## Detection Prevalence : 0.5731
## Balanced Accuracy : 0.7263
##
## 'Positive' Class : HIGH
##
results <- knn_fit$results
plot(x = results$k,
y = results$ROC,
type = "b",
pch = 19,
col = "blue",
main = "Model Performance vs K Value",
xlab = "Number of Neighbors (k)",
ylab = "ROC (AUC)")
abline(v = knn_fit$bestTune$k, col = "red", lty = 2)actual_values <- factor(data.test$quality, levels = levels(pred.knn))
final_results <- confusionMatrix(pred.knn, actual_values, mode = "prec_recall")
print(final_results)## Confusion Matrix and Statistics
##
## Reference
## Prediction HIGH LOW
## HIGH 145 51
## LOW 41 105
##
## Accuracy : 0.731
## 95% CI : (0.6807, 0.7773)
## No Information Rate : 0.5439
## P-Value [Acc > NIR] : 8.407e-13
##
## Kappa : 0.455
##
## Mcnemar's Test P-Value : 0.3481
##
## Precision : 0.7398
## Recall : 0.7796
## F1 : 0.7592
## Prevalence : 0.5439
## Detection Rate : 0.4240
## Detection Prevalence : 0.5731
## Balanced Accuracy : 0.7263
##
## 'Positive' Class : HIGH
##
نتیجهگیری نهایی و تفسیر دستاوردها:
تحلیل خروجیهای مدل KNN نتایج قابل توجهی را آشکار میسازد:
دقت کلی (Accuracy): مدل توانست به دقت بالایی دست یابد. با در نظر گرفتن پیچیدگی شیمیایی دادهها و استفاده از یک الگوریتم پایه، این نتیجه بسیار مطلوب است.
تعادل دقت و بازیابی:
انتخاب هوشمندانه K: انتخاب مقدار بهینه برای همسایگان باعث شده مدل از جزئیات نویزگونه عبور کرده و الگوهای کلیتر و پایدارتر را یاد بگیرد.
پیشنهاد برای تحقیقات آتی:
برای کاربردهای صنعتی پیشنهاد میشود از الگوریتمهای درختی مانند Random Forest یا XGBoost استفاده شود. این الگوریتمها میتوانند تعاملات غیرخطی پیچیده بین ترکیبات شیمیایی را بهتر مدلسازی کنند و احتمالاً دقت را بهبود بخشند.